﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Cronus.ViewModel;

namespace Cronus.Windows
{
    /// <summary>
    /// Interaction logic for ProjectSetup.xaml
    /// </summary>
    public partial class ProjectSetup : Window
    {
        //*** Constants ***//
        //*** Static ***//
        //*** Member Variables ***//
        DataModel _DataModel;

        //*** Properties ***//
        public DataModel DataModel
        {
            get { return _DataModel; }
            set { _DataModel = value; }
        }

        public string SelectedProjectName
        {
            get { return _ProjectComboBox.SelectedItem as string; }
        }

        //*** Constructors ***//
        public ProjectSetup()
        {
            InitializeComponent();

            _btnSaveProject.IsEnabled = false;
        }

        //*** Methods ***//
        /// <summary>
        /// This function loads data from the dataset into the fields on the form. This function may be called
        /// from any thread since it posts back to the dispatcher to execute.
        /// </summary>
        private void LoadData()
        {
            Dispatcher.BeginInvoke((Action)(() => {

                // Bind the project data
                var projectNames = from project in _DataModel.Projects
                                   orderby project.ProjectName
                                   select project.ProjectName;
                _ProjectComboBox.ItemsSource = new ObservableCollection<string>(projectNames);
                if (0 < _ProjectComboBox.Items.Count)
                {
                    _ProjectComboBox.SelectedIndex = 0;
                }
                else
                {
                    // Even though there aren't any items in the list box, call OnProjectSelected to
                    // set default values for the screen.
                    OnProjectSelected();
                }
            }));
        }

        /// <summary>
        /// This is a handler for the button when a user adds a project.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void AddNewProject_Click(object sender, RoutedEventArgs e)
        {
            if (String.Empty != _NewProjectTextBox.Text)
            {
                _DataModel.CreateProject(_NewProjectTextBox.Text, () => LoadData());
            }
        }

        /// <summary>
        /// This is a handler for the button when a user deletes a project.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void DeleteProject_Click(object sender, RoutedEventArgs e)
        {
            // Get the selected project, verify the user wants to delete it, then delete it.
            if (!String.IsNullOrEmpty(SelectedProjectName))
            {
                if (MessageBoxResult.Yes == MessageBox.Show("Are you sure you want to delete this project?  This action cannot be undone.",
                                                            Cronus.View.Properties.Resources.Title,
                                                            MessageBoxButton.YesNo))
                {
                    _DataModel.RemoveProject(SelectedProjectName, () => LoadData());
                }
            }
        }

        /// <summary>
        /// Callback when the user selects a project from the drop down.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void ProjectComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            OnProjectSelected();
        }

        /// <summary>
        /// This function is called whenever a new project is selected in the ComboBox.
        /// </summary>
        private void OnProjectSelected()
        {
            if (!String.IsNullOrEmpty(SelectedProjectName))
            {
                var project = _DataModel.Projects.FirstOrDefault(p => p.ProjectName == SelectedProjectName);

                // Find the mapped and unmapped tasks.
                _MappedTasks.ItemsSource = new ObservableCollection<string>(project.Tasks.Select(task => task.TaskName));
                _NameTextBox.Text = project.ProjectName;

                // Only allow users to delete stuff if we're not timing anything.
                _btnDelete.IsEnabled = !_DataModel.IsTiming;
            }
            else
            {
                // No selected project, just set default values.
                _MappedTasks.ItemsSource = null;
                _NameTextBox.Text = String.Empty;
                _btnDelete.IsEnabled = false;
            }

            // Always show a list of the unmapped tasks.
            _UnmappedTasks.ItemsSource = new ObservableCollection<string>(_DataModel.UnmappedTasks.Select(task => task.TaskName));
        }

        /// <summary>
        /// This function handles when the user clicks on AddSelected.
        /// </summary>
        /// <param name="sender">Used to determine which ListBox to select items from and if tasks
        /// will be mapped or unmapped.</param>
        /// <param name="e">Not used.</param>
        private void UpdateSelected_Click(object sender, RoutedEventArgs e)
        {
            // Determine if we are mapping or unmapping tasks.
            bool bMappingTasks = (sender == _AddSelected) ? (true) : (false);

            ListBox aListBox = _MappedTasks; // Assume we're unmapping at first.
            if (bMappingTasks)
            {
                aListBox = _UnmappedTasks;
            }

            Action whenDone = () => LoadData(); // We'll always do the same thing when we're done. No sense in duplication.

            // Get the selected task names as a list of strings.
            var selectedTaskNames = (IEnumerable<string>)aListBox.SelectedItems;

            // Based on if we're mapping or de-mapping, call the correct functionality.
            if (bMappingTasks)
                _DataModel.AssociateTasksWithProject(SelectedProjectName, selectedTaskNames, whenDone);
            else
                _DataModel.DisassociateTasksFromProject(SelectedProjectName, selectedTaskNames, whenDone);
        }

        /// <summary>
        /// This function handles when the user clicks on AddAll.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void AddAll_Click(object sender, RoutedEventArgs e)
        {
            var tasksToAdd = _UnmappedTasks.ItemsSource as IEnumerable<string>;
            _DataModel.AssociateTasksWithProject(SelectedProjectName, tasksToAdd, () => LoadData());
        }

        /// <summary>
        /// This function handles when the user clicks on RemoveAll.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void RemoveAll_Click(object sender, RoutedEventArgs e)
        {
            var tasksToRemove = _MappedTasks.ItemsSource as IEnumerable<string>;
            _DataModel.DisassociateTasksFromProject(SelectedProjectName, tasksToRemove, () => LoadData());
        }

        /// <summary>
        /// This function is called when the text in the name textbox changes.  This updates the 
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void NameTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Don't allow users to change the name to nothing.  A name has to exist.
            if (0 == _NameTextBox.Text.Length)
            {
                _btnSaveProject.IsEnabled = false;
            }
            else if (!String.IsNullOrEmpty(SelectedProjectName))
            {
                // If the name is different than the current name, allow users to save the changes.
                if (_NameTextBox.Text != SelectedProjectName)
                {
                    _btnSaveProject.IsEnabled = true;
                }
                else
                {
                    _btnSaveProject.IsEnabled = false;
                }
            }
        }

        /// <summary>
        /// This is a callback when the user wants to save changes to a project.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void SaveProject_Click(object sender, RoutedEventArgs e)
        {
            _DataModel.ModifyProjectName(SelectedProjectName, _NameTextBox.Text, () => LoadData());
        }

        /// <summary>
        /// This function is called as the window is activated.  It will do some startup work to
        /// make sure the window is properly setup for the user.
        /// </summary>
        /// <param name="sender">Not used.</param>
        /// <param name="e">Not used.</param>
        private void Window_Activated(object sender, EventArgs e)
        {
            // Only enable the delete button if we're not currently timing a task.
            _btnDelete.IsEnabled = true;
            if (_DataModel.IsTiming || String.IsNullOrEmpty(SelectedProjectName))
            {
                _btnDelete.IsEnabled = false;
            }
        }
    }
}
